<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Painting with Cairo in Ruby GTK</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, GTK, Cairo, drawing, Ruby, programming, Linux">
<meta name="description" content="In this part of the Ruby GTK tutorial, we do some 
painting with the Cairo library.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container2">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content2">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Painting with Cairo</h1>

<p>
In this part of the Ruby GTK tutorial, we will do some painting with the Cairo library.
</p>

<div class="big_hor">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* big_horizontal */
google_ad_slot = "2904953388";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>
<b>Cairo</b> is a library for creating 2D vector graphics. 
We can use it to draw our own widgets, charts or various effects or animations. 
</p>


<h2>Colors</h2>

<p>
In the first example, we will work with colors. A color is an object representing a 
combination of Red, Green, and Blue (RGB) intensity values. Cairo valid RGB values are 
in the range 0 to 1. 
</p>

<pre class="code">
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program shows how to work
# with colors in Cairo
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

    def initialize
        super
    
        set_title "Colors"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end
        
        init_ui

        set_default_size 360, 100
        set_window_position Gtk::Window::POS_CENTER
        
        show_all
    end
    
    def init_ui
    
        @darea = Gtk::DrawingArea.new  
        
        @darea.signal_connect "expose-event" do  
            on_expose
        end
    
        add(@darea)

    end
    
    def on_expose
    
        cr = @darea.window.create_cairo_context  
        draw_colors cr

    end 
    
    def draw_colors cr
        
        cr.set_source_rgb 0.2, 0.23, 0.9
        cr.rectangle 10, 15, 90, 60
        cr.fill
         
        cr.set_source_rgb 0.9, 0.1, 0.1
        cr.rectangle 130, 15, 90, 60
        cr.fill

        cr.set_source_rgb 0.4, 0.9, 0.4
        cr.rectangle 250, 15, 90, 60
        cr.fill
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main
</pre>

<p>
In our example, we will draw three rectangles and fill them with
three different colors. 
</p>

<pre class="explanation">
@darea = Gtk::DrawingArea.new 
</pre>

<p>
We will be doing our drawing operations on the <code>DrawingArea</code> 
widget. 
</p>

<pre class="explanation">
@darea.signal_connect "expose-event" do  
    on_expose
end
</pre>

<p>
When the window needs to be redrawn, the 
the <code>expose-event</code> is triggered. In response to this event,
we call the <code>on_expose</code> method. 
</p>

<pre class="explanation">
 cr = @darea.window.create_cairo_context  
</pre>

<p>
We create the cairo context object from the
<code>GdkWindow</code> of the drawing area. The context is an
object onto which we do all our drawings. 
</p>

<pre class="explanation">
draw_colors cr
</pre>

<p>
The actual drawing is delegated to the <code>draw_colors</code> method. 
</p>

<pre class="explanation">
cr.set_source_rgb 0.2, 0.23, 0.9
</pre>

<p>
The <code>set_source_rgb</code> method sets a color for the 
cairo context. The three parameters of the method are the color intensity
values. 
</p>

<pre class="explanation">
cr.rectangle 10, 15, 90, 60
</pre>

<p>
We draw a rectangle. The first two parameters are the x, y coordinates of the
top left corner of the rectangle. The last two parameters are the width and height
of the rectangle. 
</p>

<pre class="explanation">
 cr.fill
</pre>

<p>
We fill the inside of the rectangle with the current color. 
</p>

<img src="/img/gui/rubygtk/colors.png" alt="Colors">
<div class="figure">Figure: Colors</div>


<h2>Basic shapes</h2>

<p>
The next example draws some basic shapes onto the window. 
</p>

<pre class="code">
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This code example draws basic shapes
# with the Cairo library
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp &lt; Gtk::Window

    def initialize
        super
    
        set_title "Basic shapes"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end
        
        init_ui

        set_default_size 390, 240
        set_window_position Gtk::Window::POS_CENTER
        
        show_all
    end
    
    def init_ui
    
        @darea = Gtk::DrawingArea.new  
        
        @darea.signal_connect "expose-event" do  
            on_expose
        end
    
        add(@darea)
    end
    
    def on_expose
    
        cr = @darea.window.create_cairo_context  
        draw_shapes cr
    end
    
    def draw_shapes cr
    
        cr.set_source_rgb 0.6, 0.6, 0.6

        cr.rectangle 20, 20, 120, 80
        cr.rectangle 180, 20, 80, 80
        cr.fill

        cr.arc 330, 60, 40, 0, 2*Math::PI
        cr.fill
        
        cr.arc 90, 160, 40, Math::PI/4, Math::PI
        cr.fill

        cr.translate 220, 180
        cr.scale 1, 0.7
        cr.arc 0, 0, 50, 0, 2*Math::PI
        cr.fill
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main
</pre>

<p>
In this example, we will create a rectangle, a square, a circle, an arc and an ellipse. 
We draw outlines in blue color, insides in white. 
</p>

<pre class="explanation">
cr.rectangle 20, 20, 120, 80
cr.rectangle 180, 20, 80, 80
cr.fill
</pre>

<p>
These lines draw a rectangle and a square. 
</p>

<pre class="explanation">
cr.arc 330, 60, 40, 0, 2*Math::PI
cr.fill
</pre>

<p>
Here the <code>arc</code> method draws a full circle.
</p>

<pre class="explanation">
cr.translate 220, 180
cr.scale 1, 0.7
cr.arc 0, 0, 50, 0, 2*Math::PI
cr.fill
</pre>

<p>
The <code>translate</code> method moves the object to a specific
point. If we want to draw an oval, we do some scaling first. Here the 
<code>scale</code> method shrinks the y axis.
</p>


<img src="/img/gui/rubygtk/shapes.png" alt="Basic shapes">
<div class="figure">Figure: Basic shapes</div>


<h2>Transparent rectangles</h2>

<p>
Transparency is the quality of being able to see through a material. The easiest way to understand 
transparency is to imagine a piece of glass or water. Technically, the rays of light can go
through the glass and this way we can see objects behind the glass.
</p>

<p>
In computer graphics, we can achieve transparency effects using alpha compositing. Alpha compositing
is the process of combining an image with a background to create the appearance of partial transparency. 
The composition process uses an alpha channel. (wikipedia.org, answers.com)
</p>

<pre class="code">
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program shows transparent
# rectangles using Cairo
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp &lt; Gtk::Window

    def initialize
        super
    
        set_title "Transparent rectangles"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end
        
        init_ui

        set_default_size 590, 90
        set_window_position Gtk::Window::POS_CENTER
        
        show_all
    end
    
    def init_ui
    
        @darea = Gtk::DrawingArea.new  
        
        @darea.signal_connect "expose-event" do  
            on_expose
        end
    
        add(@darea)

    end
    
    def on_expose
    
        cr = @darea.window.create_cairo_context  
        
        for i in (1..10)
            cr.set_source_rgba 0, 0, 1, i*0.1
            cr.rectangle 50*i, 20, 40, 40
            cr.fill
        end
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main
</pre>

<p>
In the example we will draw ten rectangles with different levels of transparency. 
</p>

<pre class="explanation">
cr.set_source_rgba 0, 0, 1, i*0.1
</pre>

<p>
The last parameter of the <code>set_source_rgba</code> method is the
alpha transparency.
</p>


<img src="/img/gui/rubygtk/transparency.png" alt="Transparent rectangles">
<div class="figure">Figure: Transparent rectangles</div>


<h2>Donut</h2>

<p>
In the following example we create a complex shape by rotating a bunch of ellipses. 
</p>

<pre class="code">
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program creates a donut
# with Cairo library
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp &lt; Gtk::Window

    def initialize
        super
    
        set_title "Donut"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end
        
        init_ui

        set_default_size 350, 250
        set_window_position Gtk::Window::POS_CENTER
        
        show_all
    end
    
    def init_ui
    
        @darea = Gtk::DrawingArea.new  
        
        @darea.signal_connect "expose-event" do  
            on_expose
        end
    
        add(@darea)

    end
    
    def on_expose
    
        cr = @darea.window.create_cairo_context  
        cr.set_line_width 0.5

        w = allocation.width
        h = allocation.height
       
        cr.translate w/2, h/2
        cr.arc 0, 0, 120, 0, 2*Math::PI
        cr.stroke
         
        for i in (1..36)
            cr.save
            cr.rotate i*Math::PI/36
            cr.scale 0.3, 1
            cr.arc 0, 0, 120, 0, 2*Math::PI
            cr.restore
            cr.stroke
        end
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main
</pre>

<p>
In this example, we create a donut. The shape resembles a cookie, hence the name donut.
</p>

<pre class="explanation">
cr.translate w/2, h/2
cr.arc 0, 0, 120, 0, 2*Math::PI
cr.stroke
</pre>

<p>
In the beginning there is an ellipse. 
</p>

<pre class="explanation">
for i in (1..36)
    cr.save
    cr.rotate i*Math::PI/36
    cr.scale 0.3, 1
    cr.arc 0, 0, 120, 0, 2*Math::PI
    cr.restore
    cr.stroke
end
</pre>

<p>
After several rotations, there is a donut.
</p>


<img src="/img/gui/rubygtk/donut.jpg" alt="Donut">
<div class="figure">Figure: Donut</div>


<h2>Drawing text</h2>

<p>
In the next example, we draw some text on the window. 
</p>

<pre class="code">
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program draws text
# using Cairo
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp &lt; Gtk::Window

    def initialize
        super
    
        set_title "Soulmate"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end
        
        init_ui

        set_default_size 370, 240
        set_window_position Gtk::Window::POS_CENTER
        
        show_all
    end
    
    def init_ui
    
        @darea = Gtk::DrawingArea.new  
        
        @darea.signal_connect "expose-event" do  
            on_expose
        end
    
        add(@darea)

    end
    
    def on_expose
    
        cr = @darea.window.create_cairo_context  
        
        cr.set_source_rgb 0.1, 0.1, 0.1
         
        cr.select_font_face "Purisa", Cairo::FONT_SLANT_NORMAL, 
            Cairo::FONT_WEIGHT_NORMAL
        cr.set_font_size 13 
       
        cr.move_to 20, 30
        cr.show_text "Most relationships seem so transitory"
        cr.move_to 20, 60
        cr.show_text "They're all good but not the permanent one"
        cr.move_to 20, 120
        cr.show_text "Who doesn't long for someone to hold"
        cr.move_to 20, 150
        cr.show_text "Who knows how to love without being told"
        cr.move_to 20, 180
        cr.show_text "Somebody tell me why I'm on my own"
        cr.move_to 20, 210
        cr.show_text "If there's a soulmate for everyone"
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main
</pre>

<p>
We display part of the lyrics from the Natasha Bedingfields Soulmate song. 
</p>

<pre class="explanation">
cr.select_font_face "Purisa", Cairo::FONT_SLANT_NORMAL, 
    Cairo::FONT_WEIGHT_NORMAL
</pre>

<p>
Here we specify the font, that we use. Purisa normal.
</p>

<pre class="explanation">
cr.set_font_size 13 
</pre>

<p>
We specify the size of the font.
</p>

<pre class="explanation">
cr.move_to 20, 30
</pre>

<p>
We move to the point, where we will draw the text. 
</p>

<pre class="explanation">
cr.show_text "Most relationships seem so transitory"
</pre>

<p>
The <code>show_text</code> method draws text onto the window. 
</p>


<img src="/img/gui/rubygtk/soulmate.png" alt="Soulmate">
<div class="figure">Figure: Soulmate</div>

<p>
In this chapter of the Ruby GTK tutorial, we were painting 
with Cairo library.
</p>


<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified June 26, 2009  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>


